package jmine.tec.utils.reflection.fast.asm;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import jmine.tec.utils.reflection.fast.FastClass;
import jmine.tec.utils.reflection.fast.FastClassFactory;

/**
 * @author takeshi
 */
public class AsmFastClassFactory extends FastClassFactory {

    private final OpenClassLoader classLoader;

    private ConcurrentMap<Class<?>, FastClass> cache = new ConcurrentHashMap<Class<?>, FastClass>();

    /**
     * @param classLoader the {@link OpenClassLoader}
     */
    public AsmFastClassFactory(OpenClassLoader classLoader) {
        super();
        this.classLoader = classLoader;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FastClass forClass(Class<?> type) {
        FastClass fc = this.cache.get(type);
        if (fc != null) {
            return fc;
        }
        synchronized (this) {
            // slow shortcut
            fc = this.cache.get(type);
            if (fc != null) {
                return fc;
            }
            FastClassGenerator gen = new FastClassGenerator(type);
            byte[] data = gen.emmitFastClassBytecode();
            String clName = gen.getGeneratedClassName();
            Class<?> class1 = this.classLoader.defineClass(clName, data);
            try {
                fc = (FastClass) class1.newInstance();
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
            FastClass old = this.cache.putIfAbsent(type, fc);
            return old != null ? old : fc;
        }
    }

}
